package com.example.javaproject.thread.juc.implock;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedLongSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * Description: 利用lock 和 AQS实现一个 互斥锁
 * <br/>Author:  tianjinyong
 * <br/>Date:    2020/7/8 10:58 AM
 */
public class Mutex implements Lock, Serializable {

    /**
     * 实现AQS
     */
    private static class Sync extends AbstractQueuedLongSynchronizer {

        /**
         * 当前队列同步器 是否在独占模式下被线程使用
         *
         * @return
         */
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        /**
         * 获取同步状态（实现至AQS的回调方法）
         *
         * @param acquires
         * @return
         */
        @Override
        protected boolean tryAcquire(long acquires) {
            assert acquires == 1; // 断言传入值是否为1，其实就是限定入参必须为1
            if (compareAndSetState(0, 1)) {   // 如果更改AQS状态值1成功，代表获取同步状态成功(获取锁成功)
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        @Override
        protected boolean tryRelease(long arg) {
            assert arg == 1;
            if (getState() == 0)
                throw new IllegalMonitorStateException();
            setExclusiveOwnerThread(null);
            setState(0);
            return false;
        }

        /**
         * 提供Condition
         *
         * @return
         */
        Condition newCondition() {
            return new ConditionObject();
        }

        private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0);
        }
    }

    private final Sync sync = new Sync();

    @Override
    public void lock() {
        sync.acquire(1);
    }

    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    @Override
    public void unlock() {
        sync.release(1);
    }

    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }

    public boolean isLocked() {
        return sync.isHeldExclusively();
    }

    public boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(time));
    }
}
